
#include "nane/ScriptSystem/ScriptSystem.h"
#include "nane/ScriptSystem/ScriptSystemImpl_.h"
#include "nane/ScriptSystem/ScriptModuleImpl_.h"
#include "nane/core/assert.h"
#include "nane/core/log.h"

namespace nane
{
    ////////////////////////////////////////////////////////////////////////////////////////////////
    ScriptSystem::ScriptSystem()
        : SubSystem<IScriptSystem>( new Implementation() )
        , m( static_cast<Implementation*>(SubSystem<IScriptSystem>::m) )
    {
        
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    ScriptSystem::~ScriptSystem()
    {
        for( std::vector<Implementation::ExportedFunction>::iterator it = m->globalFunctions.begin(), it_end = m->globalFunctions.end();
            it != it_end;
            ++it )
        {
            delete it->function;
        }
        m->globalFunctions.clear();
        Shutdown();
        delete m;
        m = NULL;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    bool ScriptSystem::Initialize()
    {
        if( SubSystem<IScriptSystem>::Initialize() == false )
        {
            return false;
        }
        ExportGlobalFunction(NULL, "nane_log", MakeFunctor(Implementation::nane_log_impl));
        return true;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    ScriptModule ScriptSystem::LoadModule( const char* _moduleName, const InputPtr& _input )
    {
        NANE_ASSERT_RV( m->interface != NULL, "ScriptSystem must be initialized", NullPtr );
        NANE_ASSERT_RV( _moduleName != NULL, "Module name must be valid", NullPtr );

        ScriptModule::Implementation* scriptModuleImpl = NULL;
        IScriptModule* moduleInterface = m->interface->LoadModule(_moduleName, _input.Get());
        if( moduleInterface != NULL )
        {
            scriptModuleImpl = new ScriptModule::Implementation(m, moduleInterface, _moduleName);
        }
        ScriptModule scriptModule(scriptModuleImpl);
        if( scriptModule != NullPtr )
        {
            for( std::vector<Implementation::ExportedFunction>::iterator it = m->globalFunctions.begin(), it_end = m->globalFunctions.end();
                it != it_end;
                ++it )
            {
                scriptModule.ExportFunction(it->className.c_str(), it->functionName.c_str(), it->function);
            }
        }
        return scriptModule;
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    void ScriptSystem::ExportGlobalFunction_( const char* _className, const char* _functionName, ScriptFunctionBase* _scriptFunction )
    {
        NANE_ASSERT_R( m->interface != NULL, "ScriptSystem must be initialized" );
        NANE_ASSERT_R( _functionName != NULL, "Function name must be valid" );
        NANE_ASSERT_R( _scriptFunction != NULL, "ScriptFunctionBase must be valid" );
        m->globalFunctions.push_back(Implementation::ExportedFunction(_className ? _className : "", _functionName, _scriptFunction));
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
}   // namespace nane
